using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Xml;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using System.Web;

namespace SLMS
{
    public class SucroseLMS : IRemoteLMS
    {
        //private System.Configuration.Configuration config;
        private CookieCollection cookies;
        private string email;
        private string firstName;
        private string lastName;
        private const string ROBOT_API_URL = "https://my.neumont.edu/robot-api/";
        private string userId;

        // Properties
        public string Email
        {
            get
            {
                return this.email;
            }
        }
        public string FirstName
        {
            get
            {
                return this.firstName;
            }
        }
        public string LastName
        {
            get
            {
                return this.lastName;
            }
        }
        public string UserId
        {
            get
            {
                return this.userId;
            }
        }

        public SucroseLMS()
        {
        }

        public bool Authenticate()
        {
            return Authenticate(false);
        }

        private bool Authenticate(bool ignoreSaved)
        {
            Image banner = image.credLMSHead;
            bool retValue = false;
            try
            {
                CredentialsDialog dialog = new CredentialsDialog(ROBOT_API_URL, "Connect to LMS", "Connect to LMS", banner);
                if (ignoreSaved)
                    dialog.AlwaysDisplay = true;
                
                DialogResult result = dialog.Show();

                if (result == DialogResult.OK)
                {
                    if (CheckCredentials(dialog.Name, dialog.Password))
                    {
                        retValue = true;
                        if (dialog.SaveChecked) dialog.Confirm(true);
                    }
                    else
                    {
                        try
                        {
                            dialog.Confirm(false);
                        }
                        catch (ApplicationException applicationException)
                        {
                            if (applicationException.Message == "Credential confirmation failed.")
                            {
                                retValue = Authenticate(true);
                            }
                            throw new Exception("Error while authenticating with LMS", applicationException);
                        }
                        return false;
                    }
                }
                else
                {
                    throw new Exception("User cancelled authentication");
                }
            }
            catch (ApplicationException applicationException)
            {
                throw new Exception("Error while authenticating with LMS", applicationException);
            }
            return retValue;
        }

        private bool CheckCredentials(string username, string password)
        {
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(SucroseLMS.ValidateCertificate);
            HttpWebRequest request = WebRequest.Create(ROBOT_API_URL + "login-1?email=" + HttpUtility.UrlEncode(username) + "&password=" + HttpUtility.UrlEncode(password)) as HttpWebRequest;
            request.CookieContainer = new CookieContainer();
            HttpWebResponse wResp = request.GetResponse() as HttpWebResponse;
            this.cookies = wResp.Cookies;

            if (!this.ParseXML(wResp))
            {
                wResp.Close();
                return false;
            }

            wResp.Close();

            return true;
        }

        private string GetAPIString(API_URL apiUrl)
        {
            switch (apiUrl)
            {
                case API_URL.GetCurrentClasses:
                    return "get-current-classes-1";
                case API_URL.GetGrades:
                    return "get-grades-1";
                case API_URL.GetSupportMaterials:
                    return "get-support-material-1";
                case API_URL.GetTaskCategories:
                    return "get-task-categories-1";
                case API_URL.GetTasks:
                    return "get-tasks-1";
                case API_URL.GetTermInfo:
                    return "get-term-info-1";
                default:
                    return string.Empty;
            }
        }

        public HttpWebResponse GetResponse(HttpWebRequest wRequest)
        {
            HttpWebResponse wResponse;
            try
            {
                wRequest.CookieContainer = new CookieContainer();
                wRequest.CookieContainer.Add(this.cookies);
                wResponse = wRequest.GetResponse() as HttpWebResponse;
            }
            catch (Exception exception)
            {
                throw exception;
            }
            return wResponse;

        }

        public HttpWebResponse GetResponse(string apiUrl)
        {
            if (apiUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase) || apiUrl.StartsWith("www", StringComparison.OrdinalIgnoreCase))
            {
                throw new Exception("API_URL should be the name of the API stub and not the full URL.");
            }
            return this.GetWebResponseFromLMS(ROBOT_API_URL + apiUrl);
        }

        public HttpWebResponse GetResponse(API_URL apiUrl, string argument)
        {
            if ((argument != null) || (argument != ""))
            {
                return this.GetWebResponseFromLMS(ROBOT_API_URL + this.GetAPIString(apiUrl) + "?" + argument);
            }
            return this.GetWebResponseFromLMS(ROBOT_API_URL + this.GetAPIString(apiUrl));
        }

        public string GetResponseStreamString(string apiUrl)
        {
            if (apiUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase) || apiUrl.StartsWith("www", StringComparison.OrdinalIgnoreCase))
            {
                throw new Exception("API_URL should be the name of the API stub and not the full URL.");
            }
            StreamReader reader = new StreamReader(this.GetWebResponseFromLMS(ROBOT_API_URL + apiUrl).GetResponseStream(), Encoding.UTF8);
            string str = reader.ReadToEnd();
            reader.Close();
            return str;
        }

        public string GetResponseStreamString(API_URL apiUrl, string argument)
        {
            HttpWebResponse webResponseFromLMS;
            if ((argument != null) || (argument != ""))
            {
                webResponseFromLMS = this.GetWebResponseFromLMS(ROBOT_API_URL + this.GetAPIString(apiUrl) + "?" + argument);
            }
            else
            {
                webResponseFromLMS = this.GetWebResponseFromLMS(ROBOT_API_URL + this.GetAPIString(apiUrl));
            }
            StreamReader reader = new StreamReader(webResponseFromLMS.GetResponseStream(), Encoding.UTF8);
            string str = reader.ReadToEnd();
            reader.Close();
            return str;
        }

        private HttpWebResponse GetWebResponseFromLMS(string LMS_API_URL)
        {
            HttpWebResponse response;
            try
            {
                HttpWebRequest request = WebRequest.Create(LMS_API_URL) as HttpWebRequest;
                request.CookieContainer = new CookieContainer();
                request.CookieContainer.Add(this.cookies);
                response = request.GetResponse() as HttpWebResponse;
            }
            catch (Exception exception)
            {
                throw exception;
            }
            return response;
        }

        public XmlDocument GetXmlDocument(string apiUrl)
        {
            if (apiUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase) || apiUrl.StartsWith("www", StringComparison.OrdinalIgnoreCase))
            {
                throw new Exception("API_URL should be the name of the API stub and not the full URL.");
            }
            HttpWebResponse webResponseFromLMS = this.GetWebResponseFromLMS(ROBOT_API_URL + apiUrl);
            XmlTextReader reader = new XmlTextReader(webResponseFromLMS.GetResponseStream());
            XmlDocument document = new XmlDocument();
            document.Load(reader);
            reader.Close();
            webResponseFromLMS.Close();
            return document;

        }

        public XmlDocument GetXmlDocument(API_URL apiUrl, string argument)
        {
            HttpWebResponse webResponseFromLMS;
            if ((argument != null) || (argument != ""))
            {
                webResponseFromLMS = this.GetWebResponseFromLMS(ROBOT_API_URL + this.GetAPIString(apiUrl) + "?" + argument);
            }
            else
            {
                webResponseFromLMS = this.GetWebResponseFromLMS(ROBOT_API_URL + this.GetAPIString(apiUrl));
            }
            XmlTextReader reader = new XmlTextReader(webResponseFromLMS.GetResponseStream());
            XmlDocument document = new XmlDocument();
            document.Load(reader);
            reader.Close();
            webResponseFromLMS.Close();
            return document;
        }

        private static bool ValidateCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors errors)
        {
            return (errors == SslPolicyErrors.None);
        }

        private bool ParseXML(HttpWebResponse wResp)
        {
            XmlTextReader reader = new XmlTextReader(wResp.GetResponseStream());
            reader.ReadToFollowing("user");

            if (reader.IsEmptyElement)
            {
                reader.Close();
                return false;
            }

            XmlDocument document = new XmlDocument();
            document.Load(reader);
            reader.Close();

            XmlNode nodeUserId      = document.SelectSingleNode("user/user_id");
            XmlNode nodeEmail       = document.SelectSingleNode("user/email");
            XmlNode nodeFirstName   = document.SelectSingleNode("user/first_name");
            XmlNode nodeLastName    = document.SelectSingleNode("user/last_name");

            this.userId     = nodeUserId.InnerText;
            this.email      = nodeEmail.InnerText;
            this.firstName  = nodeFirstName.InnerText;
            this.lastName   = nodeLastName.InnerText;

            return true;
        }
    }
}
